package org.spbsu.apco.common.task.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * User: solozobov
 * Date: 12.11.12
 */

public abstract class BaseTask<D, R> {
    private static final Logger LOG = LoggerFactory.getLogger(BaseTask.class);

    private static AtomicLong nextId = new AtomicLong(0);

    private long id;
    private final List<BaseTask> subTasks;
    private transient long taskStartTime;
    private transient long taskDuration;

    protected BaseTask() {
        this(new ArrayList<BaseTask>());
    }

    protected BaseTask(final List<BaseTask> subTasks) {
        this.id = nextId.getAndIncrement();
        this.subTasks = subTasks;
    }

    public void addSubTasks(final BaseTask... subTasks) {
        Collections.addAll(this.subTasks, subTasks);
    }

    @SuppressWarnings("unchecked")
    public R runTask(final List<?> subTaskResults) {
        try {
            taskStartTime = System.currentTimeMillis();
            R result = execute((List<D>) subTaskResults);
            taskDuration = System.currentTimeMillis() - taskStartTime;
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Task failed with exception", e);
        }
    }

    public abstract R execute(final List<D> inputData) throws Exception;

    public List<BaseTask> getSubTasks() {
        return subTasks;
    }

    public long getTaskStartTime() {
        return taskStartTime;
    }

    public long getTaskDuration() {
        return taskDuration;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof BaseTask)) return false;

        BaseTask task = (BaseTask) o;

        return getId() == task.getId();

    }

    @Override
    public int hashCode() {
        return (int) (getId() ^ (getId() >>> 32));
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "{" + "id=" + getId() + '}';
    }

    public long getId() {
        return id;
    }

    public String getType() {
        return this.getClass().getSimpleName();
    }
}
